from pygame.sprite import Group, RenderUpdates
from gamesprite import *
from driver import CollisionSignal
from ai import gameAI
from tools import *
from level import *

class DataMap(object):
    PLAYER = 1
    ENEMY = 2
    BLOCK = 3
    BASE = 4
    GRID = 16
    XAXIS = 40
    YAXIS = 40
    def __init__(self, rawmap): # rawmap = (item1, item2...itemn)
        super(DataMap, self).__init__()
        self.player = Group()
        self.enemy = Group()
        self.block = Group()
        self.base = Group()
        self.bullet = Group()
        self.updates = Group()
        self.render = RenderUpdates()
        self.__ai = gameAI()
        self.__refmap = []
        for y in xrange(DataMap.YAXIS): # init reference map
            self.__refmap.append([])
            for x in xrange(DataMap.XAXIS):
                self.__refmap[y].append([])
        # create sprite
        for item in rawmap:
            spr = None
            if item[0] == DataMap.PLAYER:
                spr = Player(item[1], self)
                self.player.add(spr)
            elif item[0] == DataMap.ENEMY:
                spr = Enemy(item[1], self, self.__ai, item[2])
                self.enemy.add(spr)
            elif item[0] == DataMap.BLOCK:
                spr = Block(item[1], self)
                self.block.add(spr)
            elif item[0] == DataMap.BASE:
                spr = Base(item[1], self)
                self.base.add(spr)
            self.updates.add(spr)
            self.render.add(spr)
            self.ref_add(spr, spr.node)

    def ref_delete(self, spr):
        # out map bound
        for hold in spr.hold:
            if spr.node[0] + hold[0] < 0 \
            or spr.node[0] + hold[0] >= DataMap.XAXIS \
            or spr.node[1] + hold[1] < 0 \
            or spr.node[1] + hold[1] >= DataMap.YAXIS:
                return
        for hold in spr.hold:
            if spr in self.__refmap[spr.node[1] + hold[1]][spr.node[0] + hold[0]]:
                self.__refmap[spr.node[1] + hold[1]][spr.node[0] + hold[0]].remove(spr)

    def ref_add(self, spr, node):
        # collision test
        collision = {}
        for hold in spr.hold:
            if node[0] + hold[0] < 0 \
            or node[0] + hold[0] >= DataMap.XAXIS \
            or node[1] + hold[1] < 0 \
            or node[1] + hold[1] >= DataMap.YAXIS:
                collision[None] = True
        if not collision: # not collide map bound
            for hold in spr.hold:
                for collspr in self.__refmap[node[1] + hold[1]][node[0] + hold[0]]: # find all collided sprite
                    collision[collspr] = True
        if not collision:
            spr.node = node
            for hold in spr.hold:
                if spr not in self.__refmap[node[1] + hold[1]][node[0] + hold[0]]:
                    self.__refmap[node[1] + hold[1]][node[0] + hold[0]].append(spr)
            return False
        else: # send collision signal
            for collspr in collision.keys():
                if collspr == None:
                    spr.driver.send(CollisionSignal())
                else:
                    spr.driver.send(CollisionSignal(collspr))
                    collspr.driver.send(CollisionSignal(spr))
            return True    

    def ref_change(self, spr, desnode):
        self.ref_delete(spr)
        collision = self.ref_add(spr, desnode)
        if collision: self.ref_add(spr, spr.node) # if collided, add to source node
        return collision
    
    def get_simplemap(self):
        sm = []
        node = None
        for x in xrange(DataMap.XAXIS):
            sm.append([0] * DataMap.YAXIS)
        for spr in self.block.sprites() + self.enemy.sprites():
            for hold in spr.hold:
                sm[spr.node[1] + hold[1]][spr.node[0] + hold[0]] = 1
        return sm






















